package awesome.request.processor;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import awesome.ServerConfig;
import awesome.request.Request;
import awesome.site.proprietor.SiteProprietor;
import awesome.site.proprietor.WebObjectProprietor;

/**
 * Receives HTTP request, locates file in site proprietor, sends file.
 * 
 * @author Chris Carpenter
 *
 */
public class HttpRequestProcessor {

	private SiteProprietor siteProprietor;
	private String siteRoot;

	private enum HttpMethod {GET, HEAD, UNSUPPORTED};

	public HttpRequestProcessor(SiteProprietor _siteProprietor) {
		this.siteProprietor = _siteProprietor;
		this.siteRoot = ServerConfig.INSTANCE.getProperty("site.root");
	}
	
	/**
	 * Processes a specific HTTP request.
	 * 
	 * @param requestToProcess The Request object to process.
	 * @throws IOException
	 */
	public void processRequest(Request requestToProcess) throws IOException {
		//get input/output streams from socket
		BufferedReader connectionInput = new BufferedReader(
				new InputStreamReader(requestToProcess.getConnection().getInputStream()));
		DataOutputStream connectionOutput = new DataOutputStream(
				requestToProcess.getConnection().getOutputStream());
		
		//read request
		String request = connectionInput.readLine();
		if (request==null) {
			Logger.getLogger("awesome.access").info("Connection closed.");
			return;
		}
		request.toUpperCase();
		
		//determine method
		HttpMethod currMethod;
		if (request.startsWith("GET")) {
			currMethod = HttpMethod.GET;
		} else if (request.startsWith("HEAD")) {
			currMethod = HttpMethod.HEAD;
		} else currMethod = HttpMethod.UNSUPPORTED;

		//if unsupported method
		if (currMethod == HttpMethod.UNSUPPORTED) {
			//send error, stop
			connectionOutput.writeBytes(constructHttpHeader(501, ""));
			connectionOutput.close();
			return;
		}
		
		
		//assemble requested file
		String requestFile = siteRoot + getPathFromRequest(request);
		Logger.getLogger("awesome.access").info(
				requestToProcess.getConnection().getInetAddress() 
				+ " requested: " 
				+ requestFile);
		
		//check for directory request
		if (requestFile.endsWith(File.separator)) {
			requestFile+=ServerConfig.INSTANCE.getProperty("site.index");
		}
		
		//if file not found
		if (!siteProprietor.containsKey(requestFile)) {
			connectionOutput.writeBytes(constructHttpHeader(404, ""));
			connectionOutput.close();
			return;
		}
		
		//locate file in site proprietor
		WebObjectProprietor currProp = siteProprietor.get(requestFile);
		
		//write success header
		connectionOutput.writeBytes(
				constructHttpHeader(200, currProp.getFileType()));
		//write file
		if (currMethod == HttpMethod.GET) {
			connectionOutput.write(currProp.getWebFile());
		}
		connectionOutput.close();
	}
	
	private String constructHttpHeader(int returnCode, String fileType) {
		StringBuilder header = new StringBuilder("HTTP/1.0 ");
		
		//add return code
		switch (returnCode) {
		case 200:
			header.append( "200 OK" );
			break;
		case 400:
			header.append( "400 Bad Request" );
			break;
		case 403:
			header.append( "403 Forbidden" );
			break;
		case 404:
			header.append( "404 Not Found" );
			break;
		case 500:
			header.append( "500 Internal Server Error" );
			break;
		case 501:
			header.append( "501 Not Implemented" );
			break;
		}
		
		//server name,etc
		header.append( "\r\n" );
		header.append( "Connection: close\r\n" ); //we can't handle persistent connections
		header.append( "Server: " +
				ServerConfig.INSTANCE.getProperty("server.name") + "\r\n" );
		
		//content type
		if (fileType!=null && !fileType.equals("")) {
			header.append( "Content-Type: "+fileType+"\r\n" );
		}
		
		header.append( "\r\n" );
		return header.toString();
	}

	private String getPathFromRequest(String inputRequest){
		StringTokenizer requestTokenizer = new StringTokenizer(inputRequest);
		requestTokenizer.nextToken(); //ignore the GET/HEAD
		return requestTokenizer.nextToken().substring(1); //trim the leading seperator
	}


}
